package crp.services.api.graphql;

import com.qwlabs.graphql.relay.Connection;
import com.qwlabs.graphql.relay.Relays;
import crp.core.security.Callers;
import crp.core.security.app.AuthService;
import crp.core.security.domain.models.AuthorizeCommand;
import crp.core.security.domain.services.UserAuthorizer;
import crp.core.user.app.UserService;
import crp.services.api.graphql.models.AuthorizeInput;
import crp.services.api.graphql.models.UserPayload;
import io.quarkus.security.Authenticated;
import org.eclipse.microprofile.graphql.DefaultValue;
import org.eclipse.microprofile.graphql.GraphQLApi;
import org.eclipse.microprofile.graphql.Mutation;
import org.eclipse.microprofile.graphql.Query;

import javax.annotation.security.RolesAllowed;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.transaction.Transactional;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.Optional;

import static crp.core.security.domain.models.Permissions.AUTH_USERS_EDIT;

@GraphQLApi
@RequestScoped
@Transactional
public class UserGraphqlApi {
    private final UserService userService;
    private final AuthService authService;

    @Inject
    public UserGraphqlApi(UserService userService,
                          AuthService authService) {
        this.userService = userService;
        this.authService = authService;
    }

    @Query
    @Authenticated
    public UserPayload me() {
        return userService.searcher().byId(Callers.userId())
                .map(UserPayload::of)
                .orElse(null);
    }

    @Query
    @NotNull
    public Connection<UserPayload> users(
            Optional<String> keyword,
            @DefaultValue("0") String after,
            @DefaultValue("10") Integer first) {
        return Relays.of(userService.searcher()
                        .by(keyword.orElse(null), Relays.of(after, first)),
                UserPayload::of);
    }

    @Mutation
    @RolesAllowed(AUTH_USERS_EDIT)
    public UserPayload authorize(@NotNull @Valid AuthorizeInput input) {
        UserAuthorizer authorizer = authService.authorizer();
        AuthorizeCommand command = authorizer.createCommand(input.getUserId(), input.getRoleIds());
        authorizer.authorize(command);
        return UserPayload.of(command.getUser());
    }
}
